package com.wanfan.wanfanBrush.design.countingPolicy;

import cn.dev33.satoken.stp.StpUtil;
import com.wanfan.wanfanBrush.common.ErrorCode;
import com.wanfan.wanfanBrush.exception.BusinessException;
import com.wanfan.wanfanBrush.manager.CounterManager;
import com.wanfan.wanfanBrush.model.entity.User;
import com.wanfan.wanfanBrush.service.UserService;
import com.wanfan.wanfanBrush.utils.EmailUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.mail.MessagingException;
import java.util.concurrent.TimeUnit;

import static com.wanfan.wanfanBrush.constant.EmailConstant.*;

/**
 * 基于 Redis 的反爬虫检测策略
 */
@Service
@Slf4j
public class RedisAntiCrawlerStrategy implements AntiCrawlerStrategy {

    @Resource
    private UserService userService;

    @Resource
    private CounterManager counterManager;

    @Override
    public void detect(long loginUserId) throws BusinessException {
        //调用多少次时告警
        final int WANG_COUNT = 10;
        //超过多少次封号
        final int BAN_COUNT = 20;
        //拼接访问Key
        String key = String.format("user:access:%s", loginUserId);
        //一分钟内访问次数，180秒过期
        long count = counterManager.incrAndGetCounter(key, 1, TimeUnit.MINUTES, 180);
        //是否封号
        if (count > BAN_COUNT) {
            //踢下线
            StpUtil.kickout(loginUserId);
            //封号
            User updateUser = new User();
            updateUser.setId(loginUserId);
            updateUser.setUserRole("ban");
            userService.updateById(updateUser);
            try {
                String subject = "用户访问异常封号通知";
                String content = String.format("用户 ID %d 访问过于频繁，已被封号。", loginUserId);
                EmailUtils.sendEmail(SENDER_EMAIL, SENDER_PASSWORD, ADMIN_EMAIL, subject, content);
            } catch (MessagingException e) {
                log.error("发送封号通知邮件失败", e);
            }
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "访问太频繁，已被封号");
        }
        //是否警告
        if (count == WANG_COUNT) {
            // 向管理员发送邮件通知
            try {
                String subject = "用户访问异常警告通知";
                String content = String.format("用户 ID %d 访问过于频繁，请关注。", loginUserId);
                EmailUtils.sendEmail(SENDER_EMAIL, SENDER_PASSWORD, ADMIN_EMAIL, subject, content);
            } catch (MessagingException e) {
                log.error("发送警告通知邮件失败", e);
            }
            throw new BusinessException(ErrorCode.FORBIDDEN_ERROR, "警告访问太频繁");
        }
    }
}